#include "nldata.h"
#include "../ZPL.h"
#include "../NL.h"
#include <stdio.h>
#include <string.h>

int CNLData::m_nPrintNameIndex = 1;

CNLData::CNLData()
{
}

CNLData::~CNLData()
{
    
}

bool CNLData::AddPackageData(const string& strFs)
{
    char *token = nullptr;
    std::list<std::string> listParam;

    if(strFs.size() <= 0)
    {
        return false;
    }

    char* pFSPackage = new char[strFs.size() + 1];
    memcpy(pFSPackage, strFs.c_str(), strFs.size());
    pFSPackage[strFs.size()] = 0x00;

    /* 获取第一个子字符串 */
    token = strtok(pFSPackage, FS);
    while(token != nullptr)
    {
        listParam.push_back(token);
        token = strtok(NULL, FS);
    };

    NLDataType type = NLDataType_Unknow;
    for(auto it = listParam.begin(); it != listParam.end(); it++)
    {
        // 判断数据类型
        std::string strCmd = *it;
        strCmd = trim(strCmd);
        // 原点位置
        if(StringEqual(strCmd.substr(0, 2), "LH"))
        {
            std::string::size_type nSplitPos = strCmd.find(",");
            m_strLHX = strCmd.substr(2, nSplitPos - 2);
            m_strLHY = strCmd.substr(nSplitPos + 1);
        }
        else if(StringEqual(strCmd.substr(0, 2), "A@"))
        {
            // 不支持
        }
        // 文本字体信息
        else if(StringEqual(strCmd.substr(0, 1), "A"))
        {
            CNLDataText datatext;
            if(ParasePackageTextData(listParam, datatext))
            {
                m_listTextData.push_back(datatext);
            }
        }
        // 条码信息
        else if(StringEqual(strCmd.substr(0, 2), "B0"))
        {
            CNLDataBarcode databarcode;
            if(ParasePackageBarcodeData(listParam, databarcode))
            {
                m_listBarcodeData.push_back(databarcode);
            }
        }
    }

    delete[] pFSPackage;

    return true;
}

bool CNLData::TranslateTextData(vector<char>& vNLPackage)
{
    // 添加打印机序号
    AddVectorString(vNLPackage, "0");

    // 发送0A命令
    AddVectorString(vNLPackage, "0A");

    for(auto it = m_listTextData.begin(); it != m_listTextData.end();)
    {
        // 角度V
        AddVectorString(vNLPackage, "V");
        string strAngle = GetNLAngle((*it).m_strFontFieldOrientation);
        AddVectorString(vNLPackage, strAngle);

        // 坐标
        AddVectorString(vNLPackage, "X");
        AddVectorString(vNLPackage, (*it).m_strFOX);
        AddVectorString(vNLPackage, "Y");
        AddVectorString(vNLPackage, (*it).m_strFOY);

        // 字体编号
        AddVectorString(vNLPackage, "T");
        int nFontId = std::atoi((*it).m_strFontName.c_str());
        // 0指内部字体，1-6指windows下载的TTF字体
        if(nFontId > 0 && nFontId <= 6)
        {
            AddVectorString(vNLPackage, (*it).m_strFontName);
        }
        else
        {
            AddVectorString(vNLPackage, "0");
        }

        // 字体高度
        AddVectorString(vNLPackage, "H");
        AddVectorString(vNLPackage, (*it).m_strFontCharacterHeight);

        // 字体长度
        AddVectorString(vNLPackage, "L");
        AddVectorString(vNLPackage, (*it).m_strFontWidth);

        // 加粗
        AddVectorString(vNLPackage, "B");
        AddVectorString(vNLPackage, "000");

        it++;
        if(it != m_listTextData.end())
        {
            vNLPackage.push_back(Code_LF);
        }
    }

    return true;
}

bool CNLData::TranslateTextContext(vector<char>& vNLPackage)
{
    vNLPackage.clear();
    // 添加打印机序号
    AddVectorString(vNLPackage, "0");

    // 文本内容/图形输入到标签文本0D
    AddVectorString(vNLPackage, "0D");

    for(auto it = m_listTextData.begin(); it != m_listTextData.end(); )
    {
        AddVectorString(vNLPackage, (*it).m_strTextContext);

        it++;
        if(it != m_listTextData.end())
        {
            vNLPackage.push_back(Code_LF);
        }
    }

    return true;
}

bool CNLData::TranslateBarcodeData(vector<char>& vNLPackage)
{
    // 添加打印机序号
    AddVectorString(vNLPackage, "0");

    // 发送0A命令
    AddVectorString(vNLPackage, "0B");

    for(auto it = m_listBarcodeData.begin(); it != m_listBarcodeData.end();)
    {
        // 角度V
        AddVectorString(vNLPackage, "V");
        string strAngle = GetNLAngle("N");
        AddVectorString(vNLPackage, strAngle);

        // 坐标
        AddVectorString(vNLPackage, "X");
        AddVectorString(vNLPackage, (*it).m_strFOX);
        AddVectorString(vNLPackage, "Y");
        AddVectorString(vNLPackage, (*it).m_strFOY);

        // 条码类型
        AddVectorString(vNLPackage, "T");
        AddVectorString(vNLPackage, (*it).m_nBarcodeType, 4);

        // 条码高度
        AddVectorString(vNLPackage, "H0");

        // 条码链接代码
        AddVectorString(vNLPackage, "L");
        AddVectorString(vNLPackage, "07"); // 固定条码
        AddVectorString(vNLPackage, (*it).m_strBarcodeContext.length(), 4); // 固定条码长度
        AddVectorString(vNLPackage, "000"); // 固定条码索引000


        it++;
        if(it != m_listBarcodeData.end())
        {
            vNLPackage.push_back(Code_LF);
        }
    }

    return true;
}

bool CNLData::TranslateBarcodeContext(vector<char>& vNLPackage)
{
    vNLPackage.clear();
    // 添加打印机序号
    AddVectorString(vNLPackage, "0");

    // 文本内容/图形输入到标签文本0D
    AddVectorString(vNLPackage, "0E");

    for(auto it = m_listBarcodeData.begin(); it != m_listBarcodeData.end(); )
    {
        AddVectorString(vNLPackage, (*it).m_strBarcodeContext);

        it++;
        if(it != m_listBarcodeData.end())
        {
            vNLPackage.push_back(Code_LF);
        }
    }

    return true;
}

bool CNLData::TranslateStart(vector<char>& vNLPackage)
{
    vNLPackage.clear();
    // 添加打印机序号
    AddVectorString(vNLPackage, "0");

    // 选择标签编辑命令09
    AddVectorString(vNLPackage, "09");

    // 标签宽度
    AddVectorString(vNLPackage, "X");
    string strLabelPrefix(5 - m_strLabelWidth.size(), '0');
    AddVectorString(vNLPackage, strLabelPrefix + m_strLabelWidth);

    // 标签高度
    AddVectorString(vNLPackage, "Y");
    strLabelPrefix = string(5 - m_strLabelHeight.size(), '0');
    AddVectorString(vNLPackage, strLabelPrefix + m_strLabelHeight);

    //string strLabelName = m_strLabelName + std::to_string(m_nPrintNameIndex);
    AddVectorString(vNLPackage, m_strLabelName);

    return true;
}

bool CNLData::TranslatePrint(vector<char>& vNLPackage)
{
    vNLPackage.clear();
    // 添加打印机序号
    AddVectorString(vNLPackage, "0");

    // 选择并打印标签1B
    AddVectorString(vNLPackage, "1B");

    // 选择并打印标签1B
    AddVectorString(vNLPackage, "E");
    //string strLabelName = m_strLabelName + std::to_string(m_nPrintNameIndex++);
    AddVectorString(vNLPackage, m_strLabelName);

    // 标签数量
    AddVectorString(vNLPackage, "Q1");

    return true;
}

string CNLData::GetNLAngle(string strFontFieldOrientation)
{
    if(strFontFieldOrientation.compare("N") == 0)
    {
        return "0";
    }
    else if(strFontFieldOrientation.compare("R") == 0)
    {
        return "270";
    }
    else if(strFontFieldOrientation.compare("I") == 0)
    {
        return "180";
    }
    else if(strFontFieldOrientation.compare("B") == 0)
    {
        return "90";
    }
    return "0";
}

bool CNLData::StringEqual(const std::string& a, const std::string& b)
{
    return strcasecmp(a.c_str(), b.c_str()) == 0;
}

vector<string> CNLData::StringSplit(const string& strSrc, const string& strSplit)
{
    string::size_type pos = - 1;
    vector<string> vResult;
    string strSrcEx = strSrc + strSplit;

    int nSize = strSrcEx.size();
    for(int i = 0; i < nSize; i++)
    {
        pos = strSrcEx.find(strSplit, i);
        if(pos < nSize)
        {
            string strSub = strSrcEx.substr(i, pos - i);
            vResult.push_back(strSub);
            i = pos + strSplit.size() - 1;
        }
    }

    return vResult;
} 

std::string CNLData::trim(const std::string& str)
{
    size_t start = str.find_first_not_of(" \t\n\r");
    size_t end = str.find_last_not_of(" \t\n\r");
    
    if (start == std::string::npos || end == std::string::npos) {
        return "";
    }
    
    return str.substr(start, end - start + 1);
}

void CNLData::AddVectorString(vector<char>& vPackage, const string& strSource)
{
    for(auto it = strSource.begin(); it != strSource.end(); it++)
    {
        vPackage.push_back(*it);
    }
}

void CNLData::AddVectorString(vector<char>& vPackage, int nValue, int nLen)
{
    string strValue = std::to_string(nValue);
    string strString;
    if(strValue.length() > nValue)
    {
            strString = strValue.substr(0, nValue);
    }
    else
    {
        strString.resize(nLen - strValue.length(), '0');
        strString.append(strValue);
    }
    for(auto it = strValue.begin(); it != strValue.end(); it++)
    {
        vPackage.push_back(*it);
    }
}

bool CNLData::ParasePackageTextData(const std::list<std::string>& listParam, CNLDataText& data)
{
    for(auto it = listParam.begin(); it != listParam.end(); it++)
    {
        std::string strCmd = *it;
        strCmd = trim(strCmd);

        // 文本位置
        if(StringEqual(strCmd.substr(0, 2), "FO"))
        {
            std::string::size_type nSplitPos = strCmd.find(",");
            data.m_strFOX = strCmd.substr(2, nSplitPos - 2);
            data.m_strFOY = strCmd.substr(nSplitPos + 1);
            printf("FO: %s  %s\n", data.m_strFOX.c_str(), data.m_strFOY.c_str());
        }
        // 文本字体信息:Use Font Name to Call Font 
        else if(StringEqual(strCmd.substr(0, 2), "A@"))
        {
            // 不支持
        }
        // 文本字体信息
        else if(StringEqual(strCmd.substr(0, 1), "A"))
        {
            vector<string> vFontInfo = StringSplit(strCmd.substr(1), ",");
            int nFontSection = vFontInfo.size();
            if(nFontSection > 0)
            {
                string strFontInfo = vFontInfo[0];
                data.m_strFontName = strFontInfo.substr(0, 1);
                if(strFontInfo.size() >= 2)
                    data.m_strFontFieldOrientation = strFontInfo.substr(1, 2);
            }
            if(nFontSection > 1)
            {
                data.m_strFontCharacterHeight = vFontInfo[1];
            }
            if(nFontSection > 2)
            {
                data.m_strFontWidth = vFontInfo[2];
            }
            data.m_type = NLDataType_Text;
        }
        // 文本内容
        else if(StringEqual(strCmd.substr(0, 2), "FD"))
        {
            data.m_strTextContext = strCmd.substr(2);
        }
    }
    if(data.m_type != NLDataType_Text)
    {
        return false;
    }
    return true;
}

bool CNLData::ParasePackageBarcodeData(const std::list<std::string>& listParam, CNLDataBarcode& data)
{
    for(auto it = listParam.begin(); it != listParam.end(); it++)
    {
        std::string strCmd = *it;
        strCmd = trim(strCmd);

        // 文本位置
        if(StringEqual(strCmd.substr(0, 2), "FO"))
        {
            std::string::size_type nSplitPos = strCmd.find(",");
            data.m_strFOX = strCmd.substr(2, nSplitPos - 2);
            data.m_strFOY = strCmd.substr(nSplitPos + 1);
            printf("FO: %s  %s\n", data.m_strFOX.c_str(), data.m_strFOY.c_str());
        }
        // 文本字体信息:Use Font Name to Call Font 
        // 文本内容
        else if(StringEqual(strCmd.substr(0, 2), "FD"))
        {
            data.m_strBarcodeContext = strCmd.substr(2);
        }
        // ^B0 – Aztec Bar Code Parameters
        // Aztec
        else if(StringEqual(strCmd.substr(0, 2), "B0"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 17;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^B1 – Code 11 Bar Code 
        // 无对应
        else if(StringEqual(strCmd.substr(0, 2), "B1"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        //  ^B2 – Interleaved 2 of 5 Bar Code 
        //  BARCODE_C25INTER 
        else if(StringEqual(strCmd.substr(0, 2), "B2"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 8;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^B3 – Code 39 Bar Code 
        // BARCODE_CODE39 
        else if(StringEqual(strCmd.substr(0, 2), "B3"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 7;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^B4 – Code 49 Bar Code 
        // BARCODE_CODE49 
        else if(StringEqual(strCmd.substr(0, 2), "B4"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 19;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^B5 – Planet Code bar code 
        //  
        else if(StringEqual(strCmd.substr(0, 2), "B5"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // 没有B6

        // ^B7 – PDF417 Bar Code 
        //  BARCODE_PDF417 
        else if(StringEqual(strCmd.substr(0, 2), "B7"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 14;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^B8 – EAN-8 Bar Code 
        //  BARCODE_EANX 
        else if(StringEqual(strCmd.substr(0, 2), "B8"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 5;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^B9 – UPC-E Bar Code  
        //   BARCODE_UPCE 
        else if(StringEqual(strCmd.substr(0, 2), "B9"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 2;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // Code 93 Bar Code  
        //  
        else if(StringEqual(strCmd.substr(0, 2), "BA"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BB – CODABLOCK Bar Code  
        //  
        else if(StringEqual(strCmd.substr(0, 2), "BB"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BC – Code 128 Bar Code (Subsets A, B, and C)   
        //  
        else if(StringEqual(strCmd.substr(0, 2), "BC"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 3;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BD – UPS MaxiCode Bar Code   
        // BARCODE_MAXICODE
        else if(StringEqual(strCmd.substr(0, 2), "BD"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 15;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BE – EAN-13 Bar Code   
        // BARCODE_EANX
        else if(StringEqual(strCmd.substr(0, 2), "BE"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 6;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BF – MicroPDF417 Bar Code   
        // BARCODE_MICROPDF417
        else if(StringEqual(strCmd.substr(0, 2), "BF"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 42;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BI – Industrial 2 of 5 Bar Codes   
        // BARCODE_MICROPDF417
        else if(StringEqual(strCmd.substr(0, 2), "BI"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        //  ^BJ – Standard 2 of 5 Bar Code
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BJ"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        //  ^BK – ANSI Codabar Bar Code
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BK"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        //   ^BL – LOGMARS Bar Code
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BL"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        //   ^BM – MSI Bar Code 
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BM"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        //    ^BO – Aztec Bar Code Parameters 
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BO"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BP – Plessey Bar Code 
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BP"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        //  ^BQ – QR Code Bar Code 
        // BARCODE_QRCODE
        else if(StringEqual(strCmd.substr(0, 2), "BQ"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 58;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        //   ^BR – GS1 Databar 
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BR"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BS – UPC/EAN Extensions 
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BS"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BT – TLC39 Bar Code
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BT"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BU – UPC-A Bar Code 
        // BARCODE_UPCA
        else if(StringEqual(strCmd.substr(0, 2), "BU"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = 1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // ^BX – Data Matrix Bar Code  
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BX"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        //  ^BY – Bar Code Field Default   
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BY"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        //  ^BZ – POSTAL Bar Code   
        // 
        else if(StringEqual(strCmd.substr(0, 2), "BZ"))
        {
            data.m_type = NLDataType_Barcode;
            data.m_nBarcodeType = -1;
            data.m_strBarcodeParam = strCmd.substr(2);
        }
        // 条码内容
        else if(StringEqual(strCmd.substr(0, 2), "FD"))
        {
            data.m_strBarcodeContext = strCmd.substr(2);
        }
    }
    if(data.m_type != NLDataType_Barcode || data.m_nBarcodeType == -1)
    {
        return false;
    }
    return true;
}